package com.taomus.mytools.simplec.compiler;

import java.util.HashMap;
import java.util.Map;
import java.util.Queue;

import org.mockito.asm.Type;
import org.objectweb.asm.Opcodes;

import com.taomus.mytools.simplec.common.SyntaxTuple;

import static com.taomus.mytools.simplec.common.SyntaxTuple.*;
import com.taomus.mytools.simplec.common.WordEnum;
import com.taomus.mytools.simplec.utils.AsmUtils;
import com.taomus.mytools.simplec.utils.ErrorUtils;
import com.taomus.mytools.simplec.utils.GeneratorAdapterUtils;
import com.taomus.mytools.simplec.utils.ICode;

public class Compiler {
	AsmUtils au;
	Map<String, Integer> localNum = new HashMap<>();

	public Compiler() {
	}

	/**
	 * 根据四元组生成类的属性和get/set方法
	 */
	public Class<?> compiler(Queue<SyntaxTuple> tuplist) {
		if (!tuplist.isEmpty()) {
			au = new AsmUtils("test");
			au.createConstructor(new ICode() {
				@Override
				public void code(GeneratorAdapterUtils adapter) {
					while (true) {
						if(tuplist.isEmpty()){
							ErrorUtils.error("tuple empty");
							break;
						}
						SyntaxTuple st = tuplist.poll();
						if (st.getOpCode() == WordEnum.EOF) {
							break;
						}
						if (st.getOpCode() == WordEnum.MOV) {
							if(st.getToken(T1).getLevel() == 0){
								adapter.loadThis();
								if(st.getCode(T3) == WordEnum.NUMBER){
									adapter.push(Integer.parseInt(st.getToken(T3).getSymbol()));
									adapter.putField(st.getToken(T1).getSymbol(),int.class);
								}else{
									adapter.loadLocal(localNum.get(st.getSymbol(T3)), int.class);
									adapter.putField(st.getToken(T1).getSymbol(),int.class);
								}
								au.createField(st.getToken(T1).getSymbol(), int.class);
							}
						}else if(st.getOpCode() == WordEnum.FUNC){
								StringBuilder m = new StringBuilder();
								m.append("Object ");
								m.append(st.getSymbol(T1));
								m.append("(Object[])");
								au.createVarArgsMethod(m.toString(),new FunctionCompiler(au,tuplist));
						//四则运算
						}else if(st.getOpCode().getCode() >= WordEnum.ADD.getCode() 
								&& st.getOpCode().getCode() <= WordEnum.DIV.getCode()){
							switch(st.getCode(T1)){
							case ID:
								adapter.loadThis();
								adapter.getField(st.getSymbol(T1),int.class);
								break;
							case TEMP:
								int local = localNum.get(st.getSymbol(T1));
								adapter.loadLocal(local,int.class);
								break;
							default:
								break;
							}
							switch(st.getCode(T2)){
							case ID:
								adapter.loadThis();
								adapter.getField(st.getSymbol(T2),int.class);
								break;
							case TEMP:
								int local = localNum.get(st.getSymbol(T2));
								adapter.loadLocal(local,int.class);
								break;
							default:
								break;
							}
							if(st.getCode(T3) == WordEnum.ID){
								adapter.loadThis();
								adapter.visitInsn(Opcodes.IADD);
								adapter.putField(st.getSymbol(T3), int.class);
							}else{
								int local = adapter.newLocal(int.class);
								localNum.put(st.getSymbol(T3),local);
								switch(st.getOpCode()){
								case ADD:
									adapter.visitInsn(Opcodes.IADD);
									break;
								case MUL:
									adapter.visitInsn(Opcodes.IMUL);
									break;
								case DIV:
									adapter.visitInsn(Opcodes.IDIV);
									break;
								case SUB:
									adapter.visitInsn(Opcodes.ISUB);
									break;
								default:
									break;
								}
								adapter.storeLocal(local, int.class);
							}
						}else{
							break;
						}
					}
				}
			});
		}return au.loadClass2("test");
}}
